Skip to content
lib components / Actions and controls

Button

Communicate which actions are available and enable users to trigger them.

import { Button } from "@siteimprove/fancylib";

#Examples

Buttons are used in different contexts within the platform. To support this variety of use, the button component features properties to adjust its appearance and functionality. The most important properties are showcased here. They are split up into these categories:

#Variants

#Regular

Use the variant property when the default button implementation doesn't support your use case. Consult the table below to find out which button variant suits your use case:

VariantPurposeUsage guideline
PrimaryMost important or frequently used action on a page.Only use once per page (excluding overlays, such as modals or sidepanels). Not required on every page.
SecondaryAlternative actions to a page's primary action.Always place them directly next to a primary button.
DefaultActions of regular importance.Use when the action is neither primary or secondary in nature. Use when multiple destructive actions are needed on a page.
DestructiveActions that delete or remove data.Only use once per page (excluding overlays, such as modals or sidepanels). Use default buttons if multiple destructive actions are needed on a page.
BorderlessLess important or infrequently used actions.Always use an icon, either with or without a label.
<Button onClick={() => console.log("clicked")} variant="primary"> Primary </Button> <Button onClick={() => console.log("clicked")} variant="secondary"> Secondary </Button> <Button onClick={() => console.log("clicked")}>Default</Button> <Button onClick={() => console.log("clicked")} variant="destructive"> Destructive </Button> <Button onClick={() => console.log("clicked")} variant="borderless"> <Icon> <IconEdit /> </Icon> Borderless </Button>

#CTA

You can also use the variant property to style the button component as call-to-action (CTA) buttons. Only use CTA buttons for marketing purposes, such as requesting a free trial.

There are three CTA button variants: primary, secondary and default. When you only need a single CTA button, choose the variant that is most visually appealing within its context of use. When using multiple adjacent CTA buttons, keep the following guidelines in mind:

  • Use a different variant for each button.
  • Use the primary variant for the most important or most frequently used action.
  • Use the secondary variant for an action that serves as an alternative to the primary action.
  • Always place the secondary variant directly next to the primary variant.
  • Use the default variant for all other actions.
<Button onClick={() => console.log("clicked")} variant="ctaPrimary"> Primary </Button> <Button onClick={() => console.log("clicked")} variant="ctaSecondary"> Secondary </Button> <Button onClick={() => console.log("clicked")} variant="ctaDefault"> Default </Button>

#Visual

#Size

Use the size property to adjust a button's size. The default size is medium and should be used in most cases. Use small buttons when space is limited, such as in the Page Report. Use large buttons for page level actions, such as exporting a page to HTML. Buttons placed next to each other should all have the same size.

<Button onClick={() => console.log("clicked")} size="small"> Small </Button> <Button onClick={() => console.log("clicked")}>Medium</Button> <Button onClick={() => console.log("clicked")} size="large"> Large </Button>

#Icon

To add an icon to a button, place an Icon component inside a button component, as shown in the example below. Visit the Icons Overview page for an overview of all available Fancy icons.

Place the icon before the label, to make it appear to the left of the label. Place the icon after the label, to make it appear to the right of the label. Only place an icon to the right of the label to signal directionality. This could, for instance, be a “next” button with a chevron pointing right.

Borderless buttons should always have an icon, whether it’s accompanied by a label or not. Other button variants should only include an icon to emphasize a button’s purpose. Don’t add an icon because of aesthetic reasons. When in doubt, don’t add an icon. People with visual impairments may not see the icon at all, so make sure the button’s (aria-)label makes the button’s purpose clear.

Use buttons that only contain an icon sparingly. Use them when space is limited or the button is repeated many times on a page. Also, the icon should be universally known, such as a pen for editing, a magnifying glass for searching, or a cogwheel for settings.

<Button onClick={() => console.log("clicked")}> <Icon> <IconEdit /> </Icon> Edit item </Button> <Button onClick={() => console.log("clicked")}> Next <Icon rotation="270"> <IconChevron /> </Icon> </Button> <Button onClick={() => console.log("clicked")} aria-label="icon only button"> <Icon> <IconSettings /> </Icon> </Button> <Button onClick={() => console.log("clicked")} aria-label="icon only button with fragment"> <> <Icon> <IconShare /> </Icon> </> </Button>

#HTML content

When adding a string or a number as a child to the Button component it will be wrapped in the InlineText component to get the proper font styling. When adding an Icon component or other HTML content as a child to the Button component it will not be wrapped in the InlineText component. To get the proper font styling when using HTML code around your string or number, you should wrap it in the InlineText component yourself.

<Button onClick={() => console.log("clicked")}> <InlineText> <span aria-hidden="true">HTML content</span> <SrOnly>Reveal HTML content</SrOnly> </InlineText> </Button>

#Button group

When you have multiple buttons with similar functionality and equal importance, you can present them as a button group. To do this, place the buttons inside a <Button.Group> component, as shown in the example below. Keep the following guidelines in mind, when using button groups:.

  • Only put default variant buttons inside a button group.
  • Use the same size for every button in the button group.
  • Either provide all or none of the buttons with an icon.
  • Don't use button groups in tables. They provide a poor keyboard navigation experience.
<Button.Group aria-label="Descriptive title for the button group"> <Button> <Icon> <IconEdit /> </Icon> Edit </Button> <Button> <Icon> <IconCopy /> </Icon> Copy </Button> <Button> <Icon> <IconShare /> </Icon> Share </Button> </Button.Group>

#State

#Loading

Buttons that trigger network operations should always enter a loading state when pressed. This is done by setting the button’s loading property to true. This state communicates to users that the button’s action is being processed. Buttons that don't trigger network operations should never enter a loading state, since their actions will be carried out immediately.

<Button onClick={() => console.log("clicked")} loading> Save </Button> <Button onClick={() => console.log("clicked")} variant="ctaDefault" loading> Save </Button> <Button onClick={() => console.log("clicked")} aria-label="Save" loading> <Icon> <IconSettings /> </Icon> </Button>

#Disabled

To disable a button, set its disabled property to true. This state communicates to users that the button’s action is unavailable.

Use the disabled state sparingly. When you use it, make sure the rest of the page makes it clear why the action is unavailable and what is required to make it available. Try not to use this state for submit buttons in forms. It’s better to let users press the submit button, so the subsequent validation errors can explain, what exactly users need to do to proceed.

<Button onClick={() => console.log("clicked")} disabled> Disabled </Button> <Button onClick={() => console.log("clicked")} variant="ctaDefault" disabled> Disabled </Button> <Button onClick={() => console.log("clicked")} aria-label="icon only button" disabled> <Icon> <IconEdit /> </Icon> </Button>

When a link answers the question “What can I do?”, rather than “Where can I go?”, it should look like a button. For example, you might have a link labelled "Add users”, which navigates users to the first page of an add-user flow. To users, that label makes it feel like they're triggering an action. To visually support this impression, the link should look like a button.

The button component’s href property supports this use case. When set to a URL, the component's HTML tag will change from <button> to <a>. However, it will still look like a button.

<Button href="https://my2.siteimprove.com/Settings/Users/Create" variant="primary"> Add users </Button>

#Open in new tab or window

When a button links to a page outside the Siteimprove Platform, it's generally best to open it in a new tab or window (depending on the user's browser setting). This can be achieved by setting the openNew property to true. Only use this property in combination with the href property.

<Button href="https://siteimprove.com/en/book-a-consultation/" openNew={true} variant="ctaPrimary" > Book a time to talk to us </Button>

#Properties

#Button

PropertyDescriptionDefinedValue
childrenOptional
elementText and icons to be displayed inside the button.
onClickOptional
functionCallback for onClick events
typeOptional
"button" | "reset" | "submit"HTML attribute to define the type of the button - defaults to "button"
hrefOptional
stringURL to which the link will redirect (Should only be used for links that look like buttons)
openNewOptional
booleanIf set to true the link will be opened in a new tab (Should only be used for links that look like buttons)
sizeOptional
"large" | "medium" | "small"Controls the size of the button - defaults to medium
variantOptional
"borderless" | "ctaDefault" | "ctaPrimary" | "ctaSecondary" | "default" | "destructive" | "primary" | "secondary"How should the button look
disabledOptional
booleanCan the button be clicked
loadingOptional
booleanShould the button show a loading indicator
idOptional
stringId applied to the button
formOptional
stringId of a form element
aria-pressedOptional
booleanDefines the button as a toggle button. The value of aria-pressed describes the state of the button
aria-controlsOptional
stringIdentifies the element (or elements) whose contents or presence are controlled by the current element.
aria-labelOptional
stringDescribe what happens if the button is clicked (for icon only buttons)
aria-labelledbyOptional
stringID of an element that describes what happens if the button is clicked (for icon only buttons if aria-label is not set)
aria-describedbyOptional
stringIDs of the elements that describe the button's function
aria-expandedOptional
booleanIf the button controls a grouping of other elements, the aria-expanded state indicates whether the controlled grouping is currently expanded or collapsed.
aria-haspopupOptional
"dialog" | "false" | "grid" | "listbox" | "menu" | "tree" | "true"If true, it indicates an interactive popup element, such as menu or dialog, is present
aria-hiddenOptional
booleanIndicates whether the element is exposed to an accessibility API.
aria-roledescriptionOptional
stringA description for the role of the button
activeOptional
booleanStyles button as if it's in an active state
inStaticModeOptional
"disable" | "hide" | "show"Specifies how button looks in the static mode. Defaults to `disable`, unless `href` is provided in which case it defaults to `show`.
data-observe-keyOptional
stringUnique string, used by external script e.g. for event tracking
classNameOptional
stringCustom className that's applied to the outermost element (only intended for special cases)
styleOptional
objectStyle object to apply custom inline styles (only intended for special cases)
tabIndexOptional
numberTab index of the outermost HTML element of the component
onKeyDownOptional
functionCallback for onKeyDown event
onMouseDownOptional
functionCallback for onMouseDown event
onMouseEnterOptional
functionCallback for onMouseEnter event
onMouseLeaveOptional
functionCallback for onMouseLeave event
onFocusOptional
functionCallback for onFocus event
onBlurOptional
functionCallback for onBlur event

#Button.Group

PropertyDescriptionDefinedValue
childrenOptional
elementMust be Button components.
aria-labelOptional
stringA descriptive title for the button group
data-observe-keyOptional
stringUnique string, used by external script e.g. for event tracking
classNameOptional
stringCustom className that's applied to the outermost element (only intended for special cases)
styleOptional
objectStyle object to apply custom inline styles (only intended for special cases)

#Guidelines

#Best practices

#Variant

  • Use the variant property to choose an overall visual style that matches the button’s purpose.
  • Only use the call-to-action (CTA) variants for marketing purposes within the platform.

#Size

  • Use the size property to adjust a button's size.
  • The default size is medium and should be used in most cases.
  • Use small when space is limited, such as in the Page Report.
  • Use large buttons for page level actions, such as exporting a page to HTML.
  • Buttons placed next to each other should all have the same size.

#Icon

  • To add an icon to a button, place anicon component inside a button component.
  • Visit theicons overview page for an overview of all available Fancy icons.
  • Add an icon to a button to emphasize it's purpose. Except when using a borderless button, then always use an icon.
  • Don’t add an icon because of aesthetic reasons.
  • When in doubt, don’t add an icon.
  • Place icons to the left of the button labels. Except when they signal directionality, then place them to the right. For example: a “Next” button with a chevron pointing right.
  • People with visual impairments may not see the icon at all, so make sure the button’s (aria-)label makes the button’s purpose clear.
  • Use buttons that contain an icon, but no label, sparingly. Only use them when space is limited or the button is repeated many times on a page.
  • When a button only contains an icon, the icon should be universally known, such as a pen for editing, a magnifying glass for searching, or a cogwheel for settings.

#Button group

  • When you have adjacent buttons with similar functionality and equal importance, consider using a button group. Simply wrap the buttons in a <Button.Group> component
  • Only put default variant buttons inside a button group.
  • Use the same size for every button in the button group.
  • Either provide all or none of the buttons with an icon.
  • Don't use button groups in tables. They provide a poor keyboard navigation experience.

#State

  • Buttons that trigger network operations should always enter a loading state when pressed.
  • Buttons that don't trigger network operations should never enter a loading state.
  • Use the button’s disabled state sparingly. When you use it, make sure the rest of the page makes it clear why the action is unavailable and what is required to make it available.
  • Try not to use the disabled state for form submit buttons. It’s better to let users press the submit button, so the subsequent validation errors can explain, what exactly users need to do to proceed.
  • The href property turns the button component into a link, that still looks like a button. Use this property when you need a UI element that behaves like a link, but "feels" like a button. In other words, when its label answers the question “What can I do?”, rather than “Where can I go?”.
  • When a button links to a page outside the Siteimprove Platform, it's generally best to open it in a new tab or window. This can be achieved by setting its openNew property to true.

#Do not use when

The button’s label answers the question “Where can I go?”, rather than “What can I do?”. In that case, use the link component instead.

#Accessibility

  • Use unique, descriptive labels - avoid generic labels like learn more.
  • If a generic label can't be avoided, make sure to provide a more descriptive aria-label.
  • Always check a button's focus behavior. Sometimes, correct focus behavior is built in. For instance, when you close a modal, focus will move back to the button that opened it. However, correct focus behavior like this is not guaranteed. For example, when you press a button inside a table row to delete that row, focus will not automatically move back to the previous element.
  • If the button toggles another piece of content's visibility, add an `aria-expanded`. If the button specifically toggles a popover, modal, or dialog, also add an `aria-haspopup`.

Explore detailed guidelines for this component: Accessibility Specifications

#Writing

  • In general, use verb + object for button labels: Create policy, Add widget, Recheck page.
  • It’s okay to use a single word when the button completes a workflow (Done), cancels an action (Cancel), or closes an overlay (Close).
  • Avoid double-negatives to confirm or cancel an action: “Are you sure you want to cancel?” [OK] [Cancel].
  • Leave out articles like “the”, “a”, “an”. The more concise you can be, the better.
  • Avoid exclamation marks (!), ellipses (…), brackets () and other punctuation and symbols (&+*>|).
  • Use sentence case: Create dashboard, not Create Dashboard.

#Notable changes

#Version 0.0.x

  • There used to be a separate property for turning a default button into a CTA button. Now, the variant property also includes CTA button variants.
  • The IconOnlyButton component has been deprecated. Now, you create a button only containing an icon by placing an icon component inside a Button compoment.
  • The LinkButton component has been deprecated. This component looked like a button, but behaved like a link. Now, you achieve the same result by using the Button component and providing its href property with a URL.